#include "audio_element.h"
#include "audio_event_iface.h"
#include "audio_pipeline.h"
#include "bluetooth_service.h"
#include "board.h"
#include "esp_bt.h"
#include "esp_bt_defs.h"
#include "esp_bt_device.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_hf_client_api.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "filter_resample.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "i2s_stream.h"
#include "opus_decoder.h"
#include "opus_encoder.h"
#include "raw_stream.h"
#include "user_bt.h"
#include "user_codec.h"
#include "user_utils.h"
#include <string.h>

#define TAG "user record"

static audio_element_handle_t record_stream_init(void);
static void relink_pipeline(audio_sink_config_t config);

static const char *ble_link_tag[3] = {"i2s_reader", "debug"};
static const char *bt_link_tag[2] = {"i2s_reader", "bt_reader"};

// record pipeline
static audio_pipeline_handle_t record_pipeline;
static audio_event_iface_handle_t evt;
static audio_element_handle_t opus_encoder, ble_reader, debug;
audio_element_handle_t i2s_reader; // 对外提供的elements,用于统一的配置i2s参数

// record task
void record_task(void *param) {
    // 1. 构建各类elements
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT_WITH_TYLE_AND_CH(CODEC_ADC_I2S_PORT, 16000, 16, AUDIO_STREAM_READER, 1);
    i2s_cfg.type = AUDIO_STREAM_READER;
    i2s_reader = i2s_stream_init(&i2s_cfg);

    opus_encoder_cfg_t opus_cfg = DEFAULT_OPUS_ENCODER_CONFIG();
    opus_cfg.task_stack = 36 * 1024;
    opus_cfg.bitrate = 16000;
    opus_cfg.complexity = 0;
    opus_cfg.task_core = 1;
    opus_encoder = encoder_opus_init(&opus_cfg);

    ble_reader = record_stream_init();
    raw_stream_cfg_t raw_cfg = RAW_STREAM_CFG_DEFAULT();
    raw_cfg.type = AUDIO_STREAM_READER;
    raw_read = raw_stream_init(&raw_cfg);
    debug = debug_stream_init();

    // 创建pipeline并组装
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    record_pipeline = audio_pipeline_init(&pipeline_cfg);
    audio_pipeline_register(record_pipeline, i2s_reader, "i2s_reader");
    audio_pipeline_register(record_pipeline, opus_encoder, "encoder");
    audio_pipeline_register(record_pipeline, ble_reader, "ble_reader");
    audio_pipeline_register(record_pipeline, debug, "debug");
    audio_pipeline_register(record_pipeline, raw_read, "bt_reader");
    audio_pipeline_link(record_pipeline, bt_link_tag, 2);

    // 创建监听
    // evt = audio_event_iface_init(&(audio_event_iface_cfg_t)AUDIO_EVENT_IFACE_DEFAULT_CFG());
    // audio_pipeline_set_listener(record_pipeline, evt);

    audio_pipeline_run(record_pipeline);
    // xTaskCreatePinnedToCore(player_task, "player_task", 4096, NULL, 5, NULL, 1);

    while (1) {
        // audio_event_iface_msg_t msg;
        // if (audio_event_iface_listen(evt, &msg, 500 / portTICK_PERIOD_MS) == ESP_OK) {
        //     const char *source_tag = audio_element_get_tag((audio_element_handle_t)msg.source);

        //     if (msg.cmd == AEL_MSG_CMD_REPORT_STATUS) {
        //         audio_element_state_t state = audio_element_get_state((audio_element_handle_t)msg.source);
        //         ESP_LOGW(TAG, "[Event] %s reported status: %d", source_tag, state);
        //     } else {
        //         ESP_LOGI(TAG, "[Event] %s cmd: 0x%x", source_tag, msg.cmd);
        //     }
        // }
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
    // 不会到这里
}

typedef struct {
    bool enable[AUDIO_SINK_NUM];
    audio_sink_type_t target;
} record_link_state_t;
record_link_state_t record_link_state = {
    .enable = {true, false}, // 默认打开BT, 关闭BLE
};

// 重新配置管道
static const char *link_tag[] = {"BT", "BLE"};
void record_reconfigure(audio_sink_config_t config) {
    audio_sink_config_t tmp_config;
    record_link_state.enable[config.source] = config.enable;
    for (int i = AUDIO_SOURCE_NUM - 1; i >= 0; i--) {
        if (record_link_state.enable[i]) {
            tmp_config.enable = true;
            tmp_config.source = i;
            ESP_LOGI(TAG, "[ * ] Source %s enabled", link_tag[i]);
            relink_pipeline(tmp_config);
            return;
        }
    }
    tmp_config.enable = false;
    tmp_config.source = AUDIO_SOURCE_BLE;
    ESP_LOGI(TAG, "[ * ] No source enabled, stopping pipeline");
    relink_pipeline(tmp_config);
}

static void relink_pipeline(audio_sink_config_t config) {
    static audio_sink_type_t last_source = AUDIO_SINK_BT;
    ESP_LOGI(TAG, "[ * ] Source changed to %s, %s", link_tag[config.source], config.enable ? "enabled" : "disabled");

    audio_pipeline_stop(record_pipeline);
    audio_pipeline_wait_for_stop_with_ticks(record_pipeline, 1000 / portTICK_PERIOD_MS);
    audio_pipeline_terminate(record_pipeline);
    ESP_LOGI(TAG, "pipeline stopped, reconfigure pipeline");

    if (last_source != config.source) {
        last_source = config.source;
        if (config.source == AUDIO_SINK_BLE) {
            // audio_pipeline_breakup_elements(record_pipeline, raw_read);
            audio_pipeline_breakup_elements(record_pipeline, i2s_reader);
            audio_pipeline_register(record_pipeline, i2s_reader, "i2s_reader");
            i2s_stream_set_clk(i2s_reader, 16000, 16, 1);
            audio_pipeline_relink(record_pipeline, ble_link_tag, 2);
            ESP_LOGI(TAG, "Linking I2S reader to BLE");
        } else {
            // audio_pipeline_breakup_elements(record_pipeline, ble_reader);
            audio_pipeline_breakup_elements(record_pipeline, opus_encoder);
            audio_pipeline_register(record_pipeline, raw_read, "bt_reader");
            i2s_stream_set_clk(i2s_reader, 16000, 16, 1);
            audio_pipeline_relink(record_pipeline, bt_link_tag, 2);
            ESP_LOGI(TAG, "Linking I2S reader to BT");
        }
    }

    // if (config.source == AUDIO_SINK_BT && config.enable) {
    //     user_bt_audio_config(USER_BT_RESUME);
    // } else {
    //     user_bt_audio_config(USER_BT_PAUSE);
    // }

    if (config.enable) {
        audio_pipeline_reset_ringbuffer(record_pipeline);
        audio_pipeline_reset_elements(record_pipeline);
        audio_pipeline_change_state(record_pipeline, AEL_STATE_INIT);
        // audio_pipeline_remove_listener(record_pipeline);
        // audio_pipeline_set_listener(record_pipeline, evt);

        audio_pipeline_run(record_pipeline);
        ESP_LOGI(TAG, "Pipeline running");
    } else {
        ESP_LOGI(TAG, "Pipeline stop");
    }
}

#define USER_RECORD_DATA_IN
#ifdef USER_RECORD_DATA_IN

typedef struct {
    bool is_recording;
    encoder_process process;
} record_state_t;
record_state_t record_state;

// 注册record数据处理
void record_regist_handler(encoder_process process) { record_state.process = process; }

// record open
static esp_err_t record_open(audio_element_handle_t self) {
    ESP_LOGI(TAG, "Record element opened");
    return ESP_OK;
}

// record close
static esp_err_t record_close(audio_element_handle_t self) {
    ESP_LOGI(TAG, "Record element closed");
    return ESP_OK;
}

// record process
static int record_process(audio_element_handle_t self, char *in_buffer, int in_len) {
    int r_size = audio_element_input(self, in_buffer, in_len);

    ESP_LOGI(TAG, "Processing %d bytes of data", r_size);
    if (record_state.process && r_size >= 0) {
        record_state.process(AEL_STATE_RUNNING, (uint8_t *)in_buffer, r_size);
    }
    // 继续运行
    audio_element_report_status(self, AEL_STATUS_STATE_RUNNING);
    return r_size;
}

// record destory
static esp_err_t record_destory(audio_element_handle_t self) {
    ESP_LOGI(TAG, "Destroying record element");
    return ESP_OK;
}

// record element init
static audio_element_handle_t record_stream_init(void) {
    audio_element_cfg_t cfg = DEFAULT_AUDIO_ELEMENT_CONFIG();
    cfg.open = record_open;
    cfg.task_stack = 4 * 1024;
    cfg.close = record_close;
    cfg.process = record_process;
    cfg.destroy = record_destory;
    cfg.buffer_len = 160;
    cfg.tag = "record";
    cfg.stack_in_ext = false;

    return audio_element_init(&cfg);
}

#endif
